#include "head.h"

// 功能：建立连接
int establishConnect(char *ip, char *port){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = inet_addr(ip);
    saddr.sin_port = htons(atoi(port));

    int ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
    ERROR_CHECK(ret, -1, "connect");

    return sockfd;
}


// 功能：接收服务端发来的响应             
int TLVRecvResponse(int sockfd, train_t *train){
    bzero(train, sizeof(train_t));

    // 接收
    recv(sockfd, &train->type, sizeof(train->type), MSG_WAITALL);
    recv(sockfd, &train->len, sizeof(train->len), MSG_WAITALL);
    recv(sockfd, train->buf, train->len, MSG_WAITALL);

    return 0;
}
                                          
// 功能：给服务发送请求                   
int TLVRequest(int sockfd,const char *mess, int type){
    train_t train;
    bzero(&train, sizeof(train));

    train.type = type;
    if(mess != NULL){
        train.len = strlen(mess);
        memcpy(train.buf, mess, train.len);
        send(sockfd, &train, sizeof(int) * 2 + train.len, MSG_NOSIGNAL);
        return 0;
    }
    send(sockfd, &train, sizeof(int) * 2, MSG_NOSIGNAL);

    return 0;
}

// 功能：传送文件时，发送长度
int TLVRequestLen(int sockfd, int len){
    train_t train;
    bzero(&train, sizeof(train_t));
    
    char fileSize[16];
    bzero(fileSize, sizeof(fileSize));
    
    sprintf(fileSize, "%d", len);

    train.type = FILE_LEN;
    train.len = strlen(fileSize);
    memcpy(train.buf, fileSize, train.len);
    
    send(sockfd, &train, sizeof(int)*2 + train.len, MSG_NOSIGNAL);

    return 0;
}

// 功能：筛选用户的输入
// 返回值：
//      0：初步筛选通过
//      非0：输入有误
int filterEnter(char *userName, char *passWord){
    printf("enter userName:\n");
    scanf(" %s", userName);
    if(strlen(userName) <= 1 || strlen(userName) >= 20){
        printf("The length of the username is not compliant\n");
        return -1;
    }
    printf("enter passWord :\n");
    scanf(" %s", passWord);
    if(strlen(passWord) < 8 || strlen(passWord) > 20){
        printf("The length of the passWord is not compliant\n");
        return -1;
    }
    return 0;
}


// 功能：登录验证
int loginVerity(int sockfd){
    char userName[32];
    char passWord[64];
    
    bzero(userName, sizeof(userName));
    bzero(passWord, sizeof(passWord));
    
    // 初步筛选
    int ret = filterEnter(userName, passWord);
    if(ret != 0){
        return ret;
    }

    // 初步合格
    TLVRequest(sockfd, userName, LOGIN_USERNAME);
    
    // 收取盐值
    train_t mess;
    bzero(&mess, sizeof(train_t));
    TLVRecvResponse(sockfd, &mess);
    
    // 不是盐值，说明用户名有问题
    if(mess.type != LOGIN_SALT){
        printf("%s\n", mess.buf);
        return -1;
    }
    // 是盐值,使用盐值加密密码，并将密文发送
    struct crypt_data data;
    data.initialized = 0;

    char *hash = crypt_r(passWord, mess.buf, &data);
    if(hash == NULL){
        perror("crypt_r");
        return -1;
    }
    // 发送加密后的密码，并收取服务的响应
    TLVRequest(sockfd, hash, LOGIN_CRYPTED);

    TLVRecvResponse(sockfd, &mess);
    
    printf("server talk : %s\n", mess.buf);
    
    if(mess.type != IS_OK){
        return -1;
    }
    // 登录成功
    return 0;
}

// 功能：注册
int registerVerity(int sockfd){
    char userName[32];
    char passWord[64];
    
    bzero(userName, sizeof(userName));
    bzero(passWord, sizeof(passWord));

    // 初步筛选
    int ret = filterEnter(userName, passWord);
    if(ret != 0){
        return ret;
    }

    TLVRequest(sockfd, userName, SIGNUP_CRYPTED);

    // 接收服务传来的响应
    // 是盐值，即可以进行注册
    train_t mess;
    TLVRecvResponse(sockfd, &mess);

    if(mess.type != SIGNUP_SALT){
        printf("server talk : %s\n", mess.buf);
        return -1;
    }

    struct crypt_data data;
    data.initialized = 0;
    // 加密
    char *hash = crypt_r(passWord, mess.buf, &data);
    TLVRequest(sockfd, hash, SIGNUP_CRYPTED);
    
    TLVRecvResponse(sockfd, &mess);
    printf("server talk:%s\n", mess.buf);
    if(mess.type != IS_OK){
        return -1;
    }
    return 0; 
}
